import type { ReactElement } from 'react';
import {
    Alert,
    Checkbox,
    Form,
    PageSection,
    Text,
    TextArea,
    TextInput,
    ToggleGroup,
    ToggleGroupItem,
} from '@patternfly/react-core';
import * as yup from 'yup';
import merge from 'lodash/merge';

import type { GoogleImageIntegration } from 'types/imageIntegration.proto';

import FormMessage from 'Components/PatternFly/FormMessage';
import FormTestButton from 'Components/PatternFly/FormTestButton';
import FormSaveButton from 'Components/PatternFly/FormSaveButton';
import FormCancelButton from 'Components/PatternFly/FormCancelButton';
import ExternalLink from 'Components/PatternFly/IconText/ExternalLink';

import usePageState from '../../hooks/usePageState';
import useIntegrationForm from '../useIntegrationForm';
import type { IntegrationFormProps } from '../integrationFormTypes';

import IntegrationFormActions from '../IntegrationFormActions';
import FormLabelGroup from '../FormLabelGroup';

import {
    categoriesUtilsForRegistryScanner,
    getGoogleCredentialsPlaceholder,
} from '../../utils/integrationUtils';

const { categoriesAlternatives, getCategoriesText, matchCategoriesAlternative, validCategories } =
    categoriesUtilsForRegistryScanner;

export type GoogleIntegrationFormValues = {
    config: GoogleImageIntegration;
    updatePassword: boolean;
};

export const validationSchema = yup.object().shape({
    config: yup.object().shape({
        name: yup.string().trim().required('An integration name is required'),
        categories: yup
            .array()
            .of(yup.string().trim().oneOf(validCategories))
            .min(1, 'Must have at least one type selected')
            .required('A category is required'),
        google: yup.object().shape({
            endpoint: yup.string().trim().required('An endpoint is required'),
            project: yup.string().trim(),
            wifEnabled: yup.boolean(),
            serviceAccount: yup
                .string()
                .trim()
                .test(
                    'serviceAccount-test',
                    'Valid JSON is required for service account key',
                    (value, context: yup.TestContext) => {
                        const requirePasswordField =
                            // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                            // @ts-ignore
                            context?.from[2]?.value?.updatePassword || false;
                        const useWorkloadId = context?.parent?.wifEnabled;

                        if (!requirePasswordField || useWorkloadId) {
                            return true;
                        }
                        try {
                            JSON.parse(value as string);
                        } catch {
                            return false;
                        }
                        const trimmedValue = value?.trim();
                        return !!trimmedValue;
                    }
                ),
        }),
        skipTestIntegration: yup.bool(),
        type: yup.string().matches(/google/),
    }),
    updatePassword: yup.bool(),
});

export const defaultValues: GoogleIntegrationFormValues = {
    config: {
        id: '',
        name: '',
        categories: ['REGISTRY'],
        google: {
            endpoint: '',
            project: '',
            wifEnabled: false,
            serviceAccount: '',
        },
        autogenerated: false,
        clusterId: '',
        skipTestIntegration: false,
        type: 'google',
    },
    updatePassword: true,
};

function GoogleIntegrationForm({
    initialValues = null,
    isEditable = false,
}: IntegrationFormProps<GoogleImageIntegration>): ReactElement {
    const formInitialValues = structuredClone(defaultValues);
    if (initialValues) {
        merge(formInitialValues.config, initialValues);

        // We want to clear the password because backend returns '******' to represent that there
        // are currently stored credentials
        formInitialValues.config.google.serviceAccount = '';

        // Don't assume user wants to change password; that has caused confusing UX.
        formInitialValues.updatePassword = false;
    }
    const {
        values,
        touched,
        errors,
        dirty,
        isValid,
        setFieldValue,
        handleBlur,
        isSubmitting,
        isTesting,
        onSave,
        onTest,
        onCancel,
        message,
    } = useIntegrationForm<GoogleIntegrationFormValues>({
        initialValues: formInitialValues,
        validationSchema,
    });

    const { isCreating } = usePageState();

    function onChange(value, event) {
        return setFieldValue(event.target.id, value);
    }

    function onUpdateCredentialsChange(value, event) {
        setFieldValue('config.google.serviceAccount', '');
        return setFieldValue(event.target.id, value);
    }

    return (
        <>
            <PageSection variant="light" isFilled hasOverflowScroll>
                <Alert
                    title="Deprecation notice"
                    component="p"
                    variant={'warning'}
                    isInline
                    className="pf-v5-u-mb-lg"
                >
                    <Text>Google Container Registry will be removed in a future release.</Text>
                    <Text>
                        It is recommended to use Google Artifact Registry as a registry replacement
                        and Scanner V4 as a scanner replacement.
                    </Text>
                    <Text>
                        See the{' '}
                        <ExternalLink>
                            <a
                                href="https://cloud.google.com/container-registry/docs/deprecations/container-registry-deprecation"
                                target="_blank"
                                rel="noopener noreferrer"
                            >
                                Container Registry deprecation notice
                            </a>
                        </ExternalLink>
                        for more information.
                    </Text>
                </Alert>
                <FormMessage message={message} />
                <Form isWidthLimited>
                    <FormLabelGroup
                        label="Integration name"
                        isRequired
                        fieldId="config.name"
                        touched={touched}
                        errors={errors}
                    >
                        <TextInput
                            type="text"
                            id="config.name"
                            placeholder="(ex. Google Registry and Scanner)"
                            value={values.config.name}
                            onChange={(event, value) => onChange(value, event)}
                            onBlur={handleBlur}
                            isDisabled={!isEditable}
                        />
                    </FormLabelGroup>
                    <FormLabelGroup
                        label="Type"
                        isRequired
                        fieldId="config.categories"
                        touched={touched}
                        errors={errors}
                    >
                        <ToggleGroup id="config.categories" areAllGroupsDisabled={!isEditable}>
                            {categoriesAlternatives.map((categoriesAlternative) => {
                                const [categoriesAlternativeItem0] = categoriesAlternative;
                                const text = getCategoriesText(categoriesAlternativeItem0);
                                const isSelected = matchCategoriesAlternative(
                                    categoriesAlternative,
                                    values.config.categories
                                );
                                return (
                                    <ToggleGroupItem
                                        key={text}
                                        text={text}
                                        isSelected={isSelected}
                                        onChange={() =>
                                            setFieldValue(
                                                'config.categories',
                                                categoriesAlternativeItem0
                                            )
                                        }
                                    />
                                );
                            })}
                        </ToggleGroup>
                    </FormLabelGroup>
                    <FormLabelGroup
                        label="Registry endpoint"
                        isRequired
                        fieldId="config.google.endpoint"
                        touched={touched}
                        errors={errors}
                        helperText="example, gcr.io"
                    >
                        <TextInput
                            type="text"
                            id="config.google.endpoint"
                            value={values.config.google.endpoint}
                            onChange={(event, value) => onChange(value, event)}
                            onBlur={handleBlur}
                            isDisabled={!isEditable}
                        />
                    </FormLabelGroup>
                    <FormLabelGroup
                        label="Project"
                        fieldId="config.google.project"
                        helperText="Match images by the project of the registry. Leave empty to match all projects."
                        touched={touched}
                        errors={errors}
                    >
                        <TextInput
                            type="text"
                            id="config.google.project"
                            value={values.config.google.project}
                            onChange={(event, value) => onChange(value, event)}
                            onBlur={handleBlur}
                            isDisabled={!isEditable}
                        />
                    </FormLabelGroup>
                    <FormLabelGroup
                        fieldId="config.google.wifEnabled"
                        touched={touched}
                        errors={errors}
                    >
                        <Checkbox
                            label="Use workload identity"
                            id="config.google.wifEnabled"
                            isChecked={values.config.google.wifEnabled}
                            onChange={(event, value) => onChange(value, event)}
                            onBlur={handleBlur}
                            isDisabled={!isEditable}
                        />
                    </FormLabelGroup>
                    {!isCreating && isEditable && (
                        <FormLabelGroup
                            label=""
                            fieldId="updatePassword"
                            helperText="Enable this option to replace currently stored credentials (if any)"
                            touched={touched}
                            errors={errors}
                        >
                            <Checkbox
                                label="Update stored credentials"
                                id="updatePassword"
                                isChecked={
                                    !values.config.google.wifEnabled && values.updatePassword
                                }
                                onChange={(event, value) => onUpdateCredentialsChange(value, event)}
                                onBlur={handleBlur}
                                isDisabled={!isEditable || values.config.google.wifEnabled}
                            />
                        </FormLabelGroup>
                    )}
                    <FormLabelGroup
                        label="Service account key (JSON)"
                        isRequired={values.updatePassword && !values.config.google.wifEnabled}
                        fieldId="config.google.serviceAccount"
                        touched={touched}
                        errors={errors}
                    >
                        <TextArea
                            className="json-input"
                            isRequired={values.updatePassword && !values.config.google.wifEnabled}
                            type="text"
                            id="config.google.serviceAccount"
                            name="config.google.serviceAccount"
                            value={values.config.google.serviceAccount}
                            onChange={(event, value) => onChange(value, event)}
                            onBlur={handleBlur}
                            isDisabled={
                                !isEditable ||
                                !values.updatePassword ||
                                values.config.google.wifEnabled
                            }
                            placeholder={getGoogleCredentialsPlaceholder(
                                values.config.google.wifEnabled,
                                values.updatePassword
                            )}
                        />
                    </FormLabelGroup>
                    <FormLabelGroup
                        fieldId="config.skipTestIntegration"
                        touched={touched}
                        errors={errors}
                    >
                        <Checkbox
                            label="Create integration without testing"
                            id="config.skipTestIntegration"
                            isChecked={values.config.skipTestIntegration}
                            onChange={(event, value) => onChange(value, event)}
                            onBlur={handleBlur}
                            isDisabled={!isEditable}
                        />
                    </FormLabelGroup>
                </Form>
            </PageSection>
            {isEditable && (
                <IntegrationFormActions>
                    <FormSaveButton
                        onSave={onSave}
                        isSubmitting={isSubmitting}
                        isTesting={isTesting}
                        isDisabled={!dirty || !isValid}
                    >
                        Save
                    </FormSaveButton>
                    <FormTestButton
                        onTest={onTest}
                        isSubmitting={isSubmitting}
                        isTesting={isTesting}
                        isDisabled={!isValid}
                    >
                        Test
                    </FormTestButton>
                    <FormCancelButton onCancel={onCancel}>Cancel</FormCancelButton>
                </IntegrationFormActions>
            )}
        </>
    );
}

export default GoogleIntegrationForm;
